package com.example.tcpseverdemo;

/**
 * 功能描述：读写数据先入先出队列
 *
 * @author：ZC 创建时间：2019/5/21 10:26
 * 最后修改日期：
 */
public class FiFoUsbStream {

    private static Object lockObject = new Object();
    public int FIFO_SIZE = 10 * 1024 * 1024;
    public byte[] buffer = new byte[FIFO_SIZE];
    public int front = 0;
    private int rear = 0;

    private boolean isEmpty = true;
    private boolean isFull = false;

    public int FiFoRead(byte[] data, int length) {
        synchronized (lockObject) {
            int count = 0;
            int bufSize = getActualSize();

            if (length < 1 || isEmpty || bufSize == 0) {
                // isEmpty = true;
                return 0;
            }

            if (bufSize > length) {
                count = length;
                isEmpty = false;
            } else {
                count = bufSize;

                isEmpty = true;
            }

            if (isFull) {
                isFull = false;
            }

            if (rear > front) {
                System.arraycopy(buffer, front, data, 0, count);
                front = front + count;
            } else {
                if (count > FIFO_SIZE - front) {
                    System.arraycopy(buffer, front, data, 0, FIFO_SIZE
                            - front);
                    System.arraycopy(buffer, 0, data, FIFO_SIZE - front,
                            count - (FIFO_SIZE - front));
                } else {
                    System.arraycopy(buffer, front, data, 0, count);
                }
                front = (front + count) >= FIFO_SIZE ? (front + count - FIFO_SIZE)
                        : (front + count);
            }
            return count;
        }

    }

    public int FiFoWrite(byte[] data, int length) {
        synchronized (lockObject) {
            int count = 0;
            int bufSize = getActualSize();

            if (length < 1 || isFull) {
                isFull = true;
                return 0;
            }

            if (FIFO_SIZE - bufSize > length) {
                count = length;
                isFull = false;
            } else {
                count = FIFO_SIZE - bufSize;
                isFull = true;
            }

            if (isEmpty) {
                isEmpty = false;
            }

            if (rear >= front) {
                if (FIFO_SIZE - rear >= count) {
                    System.arraycopy(data, 0, buffer, rear, count);
                    rear = rear + count >= FIFO_SIZE ? 0 : rear + count;
                } else {
                    System.arraycopy(data, 0, buffer, rear, FIFO_SIZE
                            - rear);
                    System.arraycopy(data, FIFO_SIZE - rear, buffer, 0,
                            count - (FIFO_SIZE - rear));
                    rear = rear + count - FIFO_SIZE;
                }

            } else {
                System.arraycopy(data, 0, buffer, rear, count);
                rear = rear + count >= FIFO_SIZE ? (rear + count - FIFO_SIZE)
                        : rear + count;
            }

            return count;
        }
    }

    public int FiFoCopy(byte[] data, int length) {
        synchronized (lockObject) {
            int count = 0;
            int bufSize = getActualSize();

            if (length < 1 || isEmpty) {
                isEmpty = true;
                return 0;
            }

            if (bufSize > length) {
                count = length;
                isEmpty = false;
            } else {
                count = bufSize;
            }

            if (rear > front) {
                System.arraycopy(buffer, front, data, 0, count);
            } else {
                if (count > FIFO_SIZE - front) {
                    System.arraycopy(buffer, front, data, 0, FIFO_SIZE
                            - front);
                    System.arraycopy(buffer, 0, data, FIFO_SIZE - front,
                            count - (FIFO_SIZE - front));
                } else {
                    System.arraycopy(buffer, front, data, 0, count - front);
                }

            }
            return count;
        }
    }

    public int getActualSize() {
        synchronized (lockObject) {
            if (isEmpty == true) {
                return 0;
            } else {
                if (rear >= front) {
                    return (rear - front);
                } else {
                    return (FIFO_SIZE - (front - rear));
                }
            }
        }
    }
}

